package com.tidy.seed.interceptor;

import com.tidy.seed.annotation.ApiLog;
import com.tidy.seed.admin.system.service.ErrorLogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalDateTime;

/**
 * 接口日志拦截器：仅处理标记@ApiLog的方法/类，调用saveApiLog记录日志
 */
@Component
public class ApiLogInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(ApiLogInterceptor.class);
    // 存储每个请求的开始时间（解决并发问题）
    private final ThreadLocal<LocalDateTime> startTimeThreadLocal = new ThreadLocal<>();

    // 直接注入ErrorLogService（核心依赖）
    @Resource
    private ErrorLogService errorLogService;

    /**
     * 请求进入前：记录开始时间 + 包装请求体
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("------------ApiLogInterceptor 前置拦截 执行-----------------");
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 检查方法或类上是否有@ApiLog注解
            if (hasApiLogAnnotation(handlerMethod)) {
                // 记录开始时间
                startTimeThreadLocal.set(LocalDateTime.now());
                // 包装请求为ContentCachingRequestWrapper，确保能读取请求体
                if (!(request instanceof ContentCachingRequestWrapper)) {
                    request = new ContentCachingRequestWrapper(request);
                }
            }
        }
        return true; // 放行请求
    }

    /**
     * 请求完成后：调用saveApiLog记录日志
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("------------ApiLogInterceptor 后置拦截 执行-----------------");
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 仅处理有@ApiLog注解的方法/类
            if (hasApiLogAnnotation(handlerMethod)) {
                // 获取注解描述（方法注解优先于类注解）
                String logDesc = getApiLogDescription(handlerMethod);
                // 计算执行时间
                LocalDateTime startTime = startTimeThreadLocal.get();
                long costTime = startTime != null ?
                        Duration.between(startTime, LocalDateTime.now()).toMillis() : 0;
                // 构建日志消息
                String message = ex != null ?
                        logDesc + " - 执行异常: " + ex.getMessage() :
                        logDesc + " - 执行成功，耗时: " + costTime + "ms";

                // 调用ErrorLogService保存日志（type=1）
                errorLogService.saveApiLog(
                        request,
                        response.getStatus(),
                        message,
                        1
                );
            }
        }
        // 清理线程变量，防止内存泄漏
        startTimeThreadLocal.remove();
    }

    /**
     * 检查方法或类上是否有@ApiLog注解
     */
    private boolean hasApiLogAnnotation(HandlerMethod handlerMethod) {
        Method method = handlerMethod.getMethod();
        Class<?> controllerClass = handlerMethod.getBeanType();
        // 方法上有注解 或 类上有注解
        return method.isAnnotationPresent(ApiLog.class)
                || controllerClass.isAnnotationPresent(ApiLog.class);
    }

    /**
     * 获取日志描述（方法注解优先）
     */
    private String getApiLogDescription(HandlerMethod handlerMethod) {
        Method method = handlerMethod.getMethod();
        Class<?> controllerClass = handlerMethod.getBeanType();
        // 优先取方法上的注解描述
        if (method.isAnnotationPresent(ApiLog.class)) {
            return method.getAnnotation(ApiLog.class).value();
        }
        // 方法上没有则取类上的
        if (controllerClass.isAnnotationPresent(ApiLog.class)) {
            return controllerClass.getAnnotation(ApiLog.class).value();
        }
        return "接口操作日志"; // 默认描述
    }
}